// AUSlotsTesterDoc.cpp : implementation of the CAUSlotsTesterDoc class
//

#include "stdafx.h"
#include "AUSlotsTester.h"

#include "AUSlotsTesterDoc.h"
#include "AUSlotsOptions.h"
#include "SelectSlotMachineDlg.h"

#include "..\SpinTestMessage.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CAUSlotsTesterDoc

IMPLEMENT_DYNCREATE(CAUSlotsTesterDoc, CDocument)

BEGIN_MESSAGE_MAP(CAUSlotsTesterDoc, CDocument)
	//{{AFX_MSG_MAP(CAUSlotsTesterDoc)
	//}}AFX_MSG_MAP
	ON_COMMAND(ID_FILE_SEND_MAIL, OnFileSendMail)
	ON_UPDATE_COMMAND_UI(ID_FILE_SEND_MAIL, OnUpdateFileSendMail)
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CAUSlotsTesterDoc construction/destruction

CAUSlotsTesterDoc::CAUSlotsTesterDoc() :
	m_wpHome( this ),
	m_wpStatisticalAnalysis( this ),
	m_wpPayoutHistory( this ),
	m_wpPayoutGraph( this ),
	m_wpFullReport( this ),
	m_bfPayoutGraphImage( this )
{
	m_nSlotPort = 0;
	m_nSlotGutID = 0;
	m_bSpinning = false;
	m_bUseIntegratedSecurity = false;

	m_nSpinsPerBatch = 10000;
	m_nLinesPerSpin = 1;
	m_nBetPerLine = 100;

	m_bAutoSave = false;

	CString strBaseURL;

	strBaseURL.Format( _T( "/%08X" ), this );

	CString strPath = strBaseURL;
	strPath += _T( "/default.html" );
	m_wpHome.SetFilePath( strPath );

	GetWebServer().AddWebFile( &m_wpHome );
	GetWebServer().AddWebFileAlias( &m_wpHome, strBaseURL );

	strPath = strBaseURL;
	strPath += _T( "/stats.html" );
	m_wpStatisticalAnalysis.SetFilePath( strPath );
	GetWebServer().AddWebFile( &m_wpStatisticalAnalysis );

	strPath = strBaseURL;
	strPath += _T( "/history.html" );
	m_wpPayoutHistory.SetFilePath( strPath );
	GetWebServer().AddWebFile( &m_wpPayoutHistory );

	strPath = strBaseURL;
	strPath += _T( "/graph.html" );
	m_wpPayoutGraph.SetFilePath( strPath );
	GetWebServer().AddWebFile( &m_wpPayoutGraph );

	strPath = strBaseURL;
	strPath += _T( "/graph.bmp" );
	m_bfPayoutGraphImage.SetFilePath( strPath );
	GetWebServer().AddWebFile( &m_bfPayoutGraphImage );

	strPath = strBaseURL;
	strPath += _T( "/report.html" );
	m_wpFullReport.SetFilePath( strPath );
	GetWebServer().AddWebFile( &m_wpFullReport );

	SetWebPageDirty();
}

CAUSlotsTesterDoc::~CAUSlotsTesterDoc()
{
	CAUSlotsTesterApp* pApp = (CAUSlotsTesterApp*)AfxGetApp();
	pApp->SetWebPageDirty();

	GetWebServer().RemoveWebFile( &m_wpHome );
	GetWebServer().RemoveWebFile( &m_wpStatisticalAnalysis );
	GetWebServer().RemoveWebFile( &m_wpPayoutHistory );
	GetWebServer().RemoveWebFile( &m_wpPayoutGraph );
	GetWebServer().RemoveWebFile( &m_bfPayoutGraphImage );
	GetWebServer().RemoveWebFile( &m_wpFullReport );

	for ( int n = 0; n < m_awpGameModes.GetSize(); n++ )
	{
		CDocumentGameModeWebPage* pWP = m_awpGameModes[ n ];

		GetWebServer().RemoveWebFile( pWP );

		delete pWP;
	}
}

LPCTSTR CAUSlotsTesterDoc::GetHomeURL() const
{
	return m_wpHome.GetFilePath();
}

LPCTSTR CAUSlotsTesterDoc::GetStatisticalAnalysisURL() const
{
	return m_wpStatisticalAnalysis.GetFilePath();
}

LPCTSTR CAUSlotsTesterDoc::GetPayoutHistoryURL() const
{
	return m_wpPayoutHistory.GetFilePath();
}

LPCTSTR CAUSlotsTesterDoc::GetPayoutGraphURL() const
{
	return m_wpPayoutGraph.GetFilePath();
}

LPCTSTR CAUSlotsTesterDoc::GetPayoutGraphImageURL() const
{
	return m_bfPayoutGraphImage.GetFilePath();
}

LPCTSTR CAUSlotsTesterDoc::GetFullReportURL() const
{
	return m_wpFullReport.GetFilePath();
}

LPCTSTR CAUSlotsTesterDoc::GetGameModeURL( int nGameMode ) const
{
	for ( int n = 0; n < m_awpGameModes.GetSize(); n++ )
	{
		CDocumentGameModeWebPage* pWP = m_awpGameModes[ n ];

		if ( pWP->GetGameMode() == nGameMode )
		{
			return pWP->GetFilePath();
		}
	}

	return _T( "Unknown Game Mode" );
}

void CAUSlotsTesterDoc::SetWebPageDirty()
{
	CAUSlotsTesterApp* pApp = (CAUSlotsTesterApp*)AfxGetApp();
	pApp->SetWebPageDirty();

	m_wpHome.SetDirty( true );
	m_wpStatisticalAnalysis.SetDirty( true );
	m_wpPayoutHistory.SetDirty( true );
	m_wpPayoutGraph.SetDirty( true );
	m_bfPayoutGraphImage.SetDirty( true );
	m_wpFullReport.SetDirty( true );

	for ( int n = 0; n < m_awpGameModes.GetSize(); n++ )
	{
		CDocumentGameModeWebPage* pWP = m_awpGameModes[ n ];

		pWP->SetDirty( true );
	}
}

BOOL CAUSlotsTesterDoc::OnNewDocument()
{
	if (!CDocument::OnNewDocument())
		return FALSE;

	CSelectSlotMachineDlg dlg;

	if ( dlg.DoModal() == IDOK )
	{
		if ( dlg.GetSlotGutID() != 0 )
		{
			OpenDataSource( dlg.GetSQLServer(), dlg.UseIntegratedSecurity(), dlg.GetUser(), dlg.GetPassword(), dlg.GetDatabase() );
			
			if ( !SetSlotServer( dlg.GetSlotServerName(), dlg.GetSlotServerPort(), dlg.GetSlotGutID() ) )
			{
				return FALSE;
			}

			m_nLinesPerSpin = dlg.GetLinesPerSpin();
			m_nBetPerLine = dlg.GetBetPerLine();
			m_Results.SetBetPerLine( m_nBetPerLine );

			m_strSlotMachineName = dlg.GetSlotName();
			SetTitle( dlg.GetSlotName() );
		}
	}

	if ( m_nSlotGutID == 0 )
	{
		return FALSE;
	}

	SetWebPageDirty();

	return TRUE;
}

void CAUSlotsTesterDoc::SetPathName(LPCTSTR lpszPathName, BOOL bAddToMRU) 
{
	CDocument::SetPathName(lpszPathName, bAddToMRU);

	SetTitle( m_strSlotMachineName );
}

/////////////////////////////////////////////////////////////////////////////
// CAUSlotsTesterDoc serialization

void CAUSlotsTesterDoc::Serialize(CArchive& ar)
{
	const int nCurrentFileFormat = 2;
	int nFileFormat = nCurrentFileFormat;

	if (ar.IsStoring())
	{
		ar << nCurrentFileFormat;

		ar << m_strSlotMachineName;
		ar << m_strSQLServer;

		BOOL b = m_bUseIntegratedSecurity;

		ar << b;

		ar << m_strDatabase;

		ar << m_strSlotServer;
		ar << m_nSlotPort;

		ar << m_nSlotGutID;

		ar << m_nLinesPerSpin;
		ar << m_nBetPerLine;
	}
	else
	{
		ar >> nFileFormat;

		ar.SetObjectSchema( nFileFormat );

		if ( nFileFormat > nCurrentFileFormat )
		{
			AfxMessageBox( _T("This file format requires a newer version of the spin tester."), MB_OK );
			AfxThrowUserException();
		}

		ar >> m_strSlotMachineName;
		ar >> m_strSQLServer;

		BOOL b;
		
		ar >> b;

		if ( b )
		{
			m_bUseIntegratedSecurity = true;
		}
		else
		{
			m_bUseIntegratedSecurity = false;
		}

		ar >> m_strDatabase;

		// This should prompt for the user and password if needed.
		if ( FAILED( m_Session.Open( m_strSQLServer, m_bUseIntegratedSecurity, NULL, NULL, m_strDatabase ) ) )
		{
			AfxMessageBox( _T("Could not connect to the database."), MB_OK );
			AfxThrowUserException();
		}

		CString strSlotServer;
		ar >> strSlotServer;

		UINT nSlotPort;
		ar >> nSlotPort;

		UINT nSlotGutID;
		ar >> nSlotGutID;

		if ( !SetSlotServer( strSlotServer, nSlotPort, nSlotGutID ) )
		{
			AfxThrowUserException();
		}

		if ( nFileFormat >= 2 )
		{
			ar >> m_nLinesPerSpin;
			ar >> m_nBetPerLine;

			m_Results.SetBetPerLine( m_nBetPerLine );
		}
	}

	m_Results.Serialize( ar );

	m_aPayoutHistory.Serialize( ar );

	if ( ar.IsLoading() && nFileFormat < 2 )
	{
		m_nBetPerLine = (int)( m_Results.GetTotalBet() / m_Results.GetPaidLinesPlayed() );
		m_nLinesPerSpin = (int)( m_Results.GetPaidLinesPlayed() / ( m_aPayoutHistory.GetCount() * m_nSpinsPerBatch ) );

		m_Results.SetBetPerLine( m_nBetPerLine );
	}
}

/////////////////////////////////////////////////////////////////////////////
// CAUSlotsTesterDoc diagnostics

#ifdef _DEBUG
void CAUSlotsTesterDoc::AssertValid() const
{
	CDocument::AssertValid();
}

void CAUSlotsTesterDoc::Dump(CDumpContext& dc) const
{
	CDocument::Dump(dc);
}
#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// CAUSlotsTesterDoc commands

bool CAUSlotsTesterDoc::OpenDataSource(	LPCTSTR szSQLServer, bool bUseIntegratedSecurity, LPCTSTR szUser, LPCTSTR szPassword, LPCTSTR szDatabase )
{
	m_strSQLServer = szSQLServer;
	m_bUseIntegratedSecurity = bUseIntegratedSecurity;
	m_strDatabase = szDatabase;

	if ( FAILED( m_Session.Open( szSQLServer, bUseIntegratedSecurity, szUser, szPassword, szDatabase ) ) )
	{
		return false;
	}

	return true;
}

void CAUSlotsTesterDoc::LoadBonusGameTypes()
{
	CAUSlotsBonusGameTypes bonusgames;

	bonusgames.m_gutsid = m_nSlotGutID;

	if ( SUCCEEDED( bonusgames.Open( &m_Session ) ) )
	{
		while ( bonusgames.MoveNext() == S_OK )
		{
			m_aBonusGames.Add( bonusgames );
		}
	}
}

void CAUSlotsTesterDoc::LoadIconNames()
{
	CAUSlotsGutsIconNames icons;

	icons.m_gutsid = m_nSlotGutID;

	if ( SUCCEEDED( icons.Open( &m_Session ) ) )
	{
		while ( icons.MoveNext() == S_OK )
		{
			m_aIcons.Add( icons );
		}
	}
}

void CAUSlotsTesterDoc::LoadPayoutTypes()
{
	CAUSlotsGutsPayouts payouts;

	payouts.m_gutsid = m_nSlotGutID;

	if ( SUCCEEDED( payouts.Open( &m_Session ) ) )
	{
		while ( payouts.MoveNext() == S_OK )
		{
			m_aPayoutTypes.Add( payouts );
		}
	}
}

void CAUSlotsTesterDoc::LoadGameModes()
{
	CString strBaseURL;

	strBaseURL.Format( _T( "/%08X" ), this );

	CAUSlotsGameModes modes;

	modes.m_machId[0] = (BYTE)( m_nSlotGutID / 100 );

	if ( SUCCEEDED( modes.Open( &m_Session ) ) )
	{
		while ( modes.MoveNext() == S_OK )
		{
			m_aGameModes.Add( modes );

			CString strPath;
			strPath.Format( _T( "/%08X/Game%d.html" ), this, modes.m_gamemodeid );

			CDocumentGameModeWebPage* pWP = new CDocumentGameModeWebPage( this, modes.m_gamemodeid );

			pWP->SetFilePath( strPath );

			GetWebServer().AddWebFile( pWP );

			m_awpGameModes.Add( pWP );
		}

		m_wpFullReport.InitializeGameModes();
	}
}

bool CAUSlotsTesterDoc::SetSlotServer( LPCTSTR szServer, UINT nPort, int nSlotGutID )
{
	m_strSlotServer = szServer;
	m_nSlotPort = nPort;

	// We don't support re-using the document for another gut.
	ASSERT( m_nSlotGutID == 0 );

	m_nSlotGutID = nSlotGutID;

	LoadBonusGameTypes();
	LoadIconNames();
	LoadPayoutTypes();
	LoadGameModes();

	if ( !m_Results.Initialize( &m_Session, m_nSlotGutID ) )
	{
		AfxMessageBox( IDP_DEBUG_DATA_NOT_FOUND );
		return false;
	}

	if ( !m_SpinTester.Initialize( &m_Session, m_nSlotGutID, m_strSlotServer, m_nSlotPort ) )
	{
		AfxMessageBox( IDP_SERVER_UNAVAILABLE );
		return false;
	}

	return true;
}

LPCTSTR CAUSlotsTesterDoc::GetSlotServerName() const
{
	return m_strSlotServer;
}

UINT CAUSlotsTesterDoc::GetSlotServerPort() const
{
	return m_nSlotPort;
}

int CAUSlotsTesterDoc::GetSlotGutID() const
{
	return m_nSlotGutID;
}

void CAUSlotsTesterDoc::OnIdle()
{
	if ( m_SpinTester.AreResultsReady() )
	{
		if ( m_SpinTester.DidResultsFail() )
		{
			OnSpinResultsFailed();
		}
		else
		{
			OnSpinResultsReady( m_SpinTester.GetResults() );
		}
	}
}

void CAUSlotsTesterDoc::OnSpinResultsReady( const CSpinTestResults* pSpinResults )
{
	m_Results.AccumulateResults( pSpinResults );

	double dCurrentPayout = m_Results.GetTotalPayoutPercent();

	m_aPayoutHistory.Add( dCurrentPayout );

	SetModifiedFlag();

	if ( m_bAutoSave )
	{
		OnFileSave();
	}

	if ( m_bSpinning )
	{
		m_SpinTester.Spin( m_nSpinsPerBatch, m_nLinesPerSpin, m_nBetPerLine );
	}
	else
	{
		m_SpinTester.ResetResults();
	}

	SetWebPageDirty();

	UpdateAllViews( NULL );
}

void CAUSlotsTesterDoc::OnSpinResultsFailed()
{
	m_bSpinning = false;
	m_SpinTester.ResetResults();
}

void CAUSlotsTesterDoc::Spin( bool bSpin )
{
	if ( bSpin != m_bSpinning )
	{
		m_bSpinning = bSpin;

		if ( m_bSpinning )
		{
			m_SpinTester.Spin( m_nSpinsPerBatch, m_nLinesPerSpin, m_nBetPerLine );
		}

		SetWebPageDirty();
	}
}

bool CAUSlotsTesterDoc::IsSpinning() const
{
	return m_bSpinning;
}

CAUSlotsTesterDoc::SPIN_STATE CAUSlotsTesterDoc::GetSpinState() const
{
	SPIN_STATE ss = ssStopped;

	if ( IsSpinning() )
	{
		ss = ssSpinning;
	}
	else if ( m_SpinTester.IsSpinning() )
	{
		ss = ssStopping;
	}

	return ss;
}

const CSpinTestResults& CAUSlotsTesterDoc::GetResults() const
{
	return m_Results;
}

void CAUSlotsTesterDoc::SetAutoSave( bool bAutoSave )
{
	m_bAutoSave = bAutoSave;

	if ( m_bAutoSave )
	{
		OnFileSave();
	}
}

bool CAUSlotsTesterDoc::IsAutoSaveOn() const
{
	return m_bAutoSave;
}

LPCTSTR CAUSlotsTesterDoc::GetGameModeName( int nGameMode ) const
{
	for ( int n = 0; n < m_aGameModes.GetSize(); n++ )
	{
		if ( m_aGameModes[ n ].m_nID == nGameMode )
		{
			return m_aGameModes[ n ].m_strDescription;
		}
	}

	ASSERT( false );

	return _T( "Unknown Game Mode" );
}

LPCTSTR CAUSlotsTesterDoc::GetIconName( int nIcon ) const
{
	for ( int n = 0; n < m_aIcons.GetSize(); n++ )
	{
		if ( m_aIcons[ n ].m_nID == nIcon )
		{
			return m_aIcons[ n ].m_strName;
		}
	}

	ASSERT( false );

	return _T( "Unknown Icon" );
}

LPCTSTR CAUSlotsTesterDoc::GetBonusGameTypeName( int nBonusGameType ) const
{
	for ( int n = 0; n < m_aBonusGames.GetSize(); n++ )
	{
		if ( m_aBonusGames[ n ].m_nID == nBonusGameType )
		{
			return m_aBonusGames[ n ].m_strDescription;
		}
	}

	ASSERT( false );

	return _T( "Unknown Bonus Game Type" );
}

LPCTSTR CAUSlotsTesterDoc::GetPayoutTypeName( int nPayoutType ) const
{
	for ( int n = 0; n < m_aPayoutTypes.GetSize(); n++ )
	{
		if ( m_aPayoutTypes[ n ].m_nID == nPayoutType )
		{
			return m_aPayoutTypes[ n ].m_strName;
		}
	}

	ASSERT( false );

	return _T( "Unknown Payout Type" );
}

const CAUSlotsTesterDoc::CPayoutHistoryArray& CAUSlotsTesterDoc::GetPayoutHistoryArray() const
{
	return m_aPayoutHistory;
}

const CGameModeArray& CAUSlotsTesterDoc::GetGameModeArray() const
{
	return m_aGameModes;
}

int CAUSlotsTesterDoc::GetPaidLinesPerBatch() const
{
	return m_nSpinsPerBatch * m_nLinesPerSpin;
}

int CAUSlotsTesterDoc::GetLinesPerSpin() const
{
	return m_nLinesPerSpin;
}

int CAUSlotsTesterDoc::GetBetPerLine() const
{
	return m_nBetPerLine;
}
